package com.ap.core.ldap.dao.impl;

import com.ap.core.ldap.dao.api.AbstractLdapZappUserDao;
import com.ap.core.ldap.dao.api.LdapZappUserDao;
import com.ap.core.ldap.domain.LdapAttribute;
import com.ap.core.ldap.domain.LdapZappUser;
import com.ap.core.ldap.domain.LdapZappUserAttributeMapper;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;

import javax.naming.directory.*;
import java.util.List;

/**
 * Implementation Class for {@link LdapZappUserDao}
 */
public class LdapZappUserDaoImpl extends AbstractLdapZappUserDao<LdapZappUser> implements LdapZappUserDao {

    /**
     * {@inheritDoc}
     */
    @Override
    public List<LdapZappUser> findAll(String objectClassName) {
    	
    	   AndFilter andFilter = new AndFilter();
           andFilter.and(new EqualsFilter("objectclass", objectClassName));
        return ldapTemplate.search("", andFilter.encode(), new LdapZappUserAttributeMapper());

    }
    
    
   
    /**
     * {@inheritDoc}
     */
    @Override
    public void persist(LdapZappUser ldapZappUser) {
        final Attributes personAttributes = new BasicAttributes();
        final BasicAttribute personBasicAttribute = new BasicAttribute("objectclass");
        for (String objectClassName : ldapZappUser.getObjectClassNames()) {
            personBasicAttribute.add(objectClassName);
        }
        personAttributes.put(personBasicAttribute);

        for (LdapAttribute<?> ldapAttribute : ldapZappUser.getLdapAttributes()) {
            personAttributes.put(ldapAttribute.getLdapAttributeName(), ldapAttribute.getLdapAttributeValue());
        }

        // Insert new zapp user in  LDAP schema
        DistinguishedName newZappUser = new DistinguishedName(ldapZappUser.getDistinguishedGroupName());
        newZappUser.add("cn", ldapZappUser.getCommonName().getLdapAttributeValue());
        ldapTemplate.bind(newZappUser, null, personAttributes);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<LdapZappUser> findByLdapAttribute(String objectClassName, LdapAttribute<?>... ldapAttributes) {
        AndFilter andFilter = new AndFilter();
        andFilter.and(new EqualsFilter("objectclass", objectClassName));
        for (LdapAttribute<?> ldapAttribute : ldapAttributes) {
            andFilter.and(new EqualsFilter(ldapAttribute.getLdapAttributeName(), (String) ldapAttribute.getLdapAttributeValue()));
        }
        return ldapTemplate.search("", andFilter.encode(), new LdapZappUserAttributeMapper());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected String getDistinguishedGroup() {
        return LdapZappUser.getDistinguishedGroup();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void checkThenPersistAndAddAttribute(LdapZappUser ldapZappUser, String destinationAttribute, String userTree) {

        List<LdapZappUser> existingLdapZappUserList = findByLdapAttribute("person", ldapZappUser.getEmailId());

        if (!existingLdapZappUserList.isEmpty()) {
            // Delete existing record
            LdapZappUser existingLdapZappUser = existingLdapZappUserList.get(0);
            DistinguishedName existingZappUser = new DistinguishedName(ldapZappUser.getDistinguishedGroupName());
            existingZappUser.add("cn", existingLdapZappUser.getCommonName().getLdapAttributeValue());
            delete(existingZappUser);
            LdapAttribute<String> ldapAttribute = new LdapAttribute<>(destinationAttribute);
            ldapAttribute.setLdapAttributeValue("cn=" + existingLdapZappUser.getCommonName().getLdapAttributeValue() + "," + existingLdapZappUser.getDistinguishedGroupName() + "," + userTree);
            removeAttribute(ldapAttribute);
        }


        persist(ldapZappUser);

        LdapAttribute<String> ldapAttribute = new LdapAttribute<>(destinationAttribute);
        ldapAttribute.setLdapAttributeValue("cn=" + ldapZappUser.getCommonName().getLdapAttributeValue() + "," + ldapZappUser.getDistinguishedGroupName() + "," + userTree);


        addAttribute(ldapAttribute);

    }

    @Override
    public void merge(String commonName, LdapAttribute<?> ldapAttribute) {
        final LdapAttribute<String> commonNameLdapAttribute = new LdapAttribute<>("cn");
        commonNameLdapAttribute.setLdapAttributeValue(commonName);

        List<LdapZappUser> existingLdapZappUserList = findByLdapAttribute("person", commonNameLdapAttribute);

        if (!existingLdapZappUserList.isEmpty()) {
            // Delete existing record
            LdapZappUser existingLdapZappUser = existingLdapZappUserList.get(0);
            replaceAttribute(existingLdapZappUser, ldapAttribute);
        }

    }

    private void replaceAttribute(LdapZappUser existingLdapZappUser, LdapAttribute<?> ldapAttribute) {
        DistinguishedName distinguishedName = new DistinguishedName(existingLdapZappUser.getDistinguishedGroupName());
        distinguishedName.add("cn", existingLdapZappUser.getCommonName().getLdapAttributeValue());

        Attribute memberInfoAttribute = new BasicAttribute(ldapAttribute.getLdapAttributeName(), ldapAttribute.getLdapAttributeValue());
        ModificationItem memberInfoItem = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, memberInfoAttribute);
        try{
            ldapTemplate.modifyAttributes(distinguishedName, new ModificationItem[]{memberInfoItem});
        } catch(org.springframework.ldap.AttributeInUseException exception){
            // This catch block if for idempotent transaction if attribute was not added in previous run where db transaction failed.
            LOG.info("The attribute not existed so not able to delete it for group Consumerusers = " + ldapAttribute.getLdapAttributeValue());
        }
    }

    }
